package org.jeecg.modules.system.controller;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.mock.JeecgMockMultipartFile;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.common.util.filter.FileTypeFilter;
import org.jeecg.modules.system.util.ContentTypeCheck;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @Author scott
 * @since 2018-12-20
 */
@Slf4j
@RestController
@RequestMapping("/sys/common")
public class CommonController {

    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;

    /**
     * 本地：local minio：minio 阿里：alioss
     */
    @Value(value = "${jeecg.uploadType}")
    private String uploadType;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * @return
     * @Author 政辉
     */
    @GetMapping("/403")
    public Result<?> noauth() {
        return Result.error("没有权限，请联系管理员授权");
    }

    /**
     * 文件上传统一方法
     *
     * @param request
     * @param response
     * @return
     */
    @PostMapping(value = "/upload")
    public Result<?> upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Result<?> result = new Result<>();
        String savePath = "";
        String bizPath = request.getParameter("biz");

        /* 文件上传，如果biz为空则默认赋值，当前日期做为biz。  by zhaowl 20211210 start*/
        if (oConvertUtils.isEmpty(bizPath)) {
            bizPath = DateUtils.getDataString(new SimpleDateFormat("yyyyMMdd"));
        }
        /* 文件上传，如果biz为空则默认赋值，当前日期做为biz。  by zhaowl 20211210 end*/

        //LOWCOD-2580 sys/common/upload接口存在任意文件上传漏洞
        if (oConvertUtils.isNotEmpty(bizPath)) {
            if (bizPath.contains(SymbolConstant.SPOT_SINGLE_SLASH) || bizPath.contains(SymbolConstant.SPOT_DOUBLE_BACKSLASH)) {
                throw new JeecgBootException("上传目录bizPath，格式非法！");
            }
        }

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 获取上传文件对象
        MultipartFile file = multipartRequest.getFile("file");
        /** 文件类型限制 by zhaowl 20211220 start */
        if (!ContentTypeCheck.contains(file.getContentType())) {
            return Result.error("不允许上传此文件类型");
        }
        /** 文件类型限制 by zhaowl 20211220 end */

        /* 文件上传支持自定义文件名称 入参fileName by zhaowl 20210524 start*/
        String fileName = request.getParameter("fileName");
        if (oConvertUtils.isNotEmpty(fileName)) {
            try {
                file = new JeecgMockMultipartFile(fileName, fileName, file.getContentType(), file.getBytes());
            } catch (IOException e) {
                throw new JeecgBootException(e);
            }
        }
        /* 文件上传支持自定义文件名称 入参fileName by zhaowl 20210524 end*/

        if (oConvertUtils.isEmpty(bizPath)) {
            if (CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)) {
                //未指定目录，则用阿里云默认目录 upload
                bizPath = "upload";
                //result.setMessage("使用阿里云文件上传时，必须添加目录！");
                //result.setSuccess(false);
                //return result;
            } else {
                bizPath = "";
            }
        }
        if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
            //update-begin-author:liusq date:20221102 for: 过滤上传文件类型
            FileTypeFilter.fileTypeFilter(file);
            //update-end-author:liusq date:20221102 for: 过滤上传文件类型
            //update-begin-author:lvdandan date:20200928 for:修改JEditor编辑器本地上传
            savePath = this.uploadLocal(file, bizPath);
            //update-begin-author:lvdandan date:20200928 for:修改JEditor编辑器本地上传
            /**  富文本编辑器及markdown本地上传时，采用返回链接方式
             //针对jeditor编辑器如何使 lcaol模式，采用 base64格式存储
             String jeditor = request.getParameter("jeditor");
             if(oConvertUtils.isNotEmpty(jeditor)){
             result.setMessage(CommonConstant.UPLOAD_TYPE_LOCAL);
             result.setSuccess(true);
             return result;
             }else{
             savePath = this.uploadLocal(file,bizPath);
             }
             */
        } else {
            //update-begin-author:taoyan date:20200814 for:文件上传改造
            savePath = CommonUtils.upload(file, bizPath, uploadType);
            //update-end-author:taoyan date:20200814 for:文件上传改造
        }
        if (oConvertUtils.isNotEmpty(savePath)) {
            result.setMessage(savePath);
            result.setSuccess(true);
        } else {
            //result.setMessage("上传失败！");
            //result.setSuccess(false);
            throw new JeecgBootException("上传失败！");
        }
        return result;
    }

    @GetMapping("/share")
    public Result<String> share(@RequestParam String fileName) {
        String path = MinioUtil.share(fileName);
        return Result.OK(path);
    }

    /**
     * 文件是否存在（用于文件秒传）
     *
     * @param fileMd5 文件MD5
     * @return 存在：文件地址
     */
    @GetMapping("/exist")
    public Result<?> exist(@RequestParam String fileMd5) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String fileKey = fileMd5 + sysUser.getId();
        Object url = redisUtil.get(fileKey);
        return Result.OK("", url);
    }

    /**
     * 文件分片请求
     *
     * @param parts    分片数量
     * @param filename 文件名称
     * @return
     */
    @GetMapping(path = "/fragment")
    public Result<?> fragment(@RequestParam Integer parts, @RequestParam String filename) {
        Map<String, Object> map = null;
        if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
            map = MinioUtil.fragment(parts, filename);
        } else if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
            map = this.fragmentLocal(parts, filename);
        } else {
            return Result.error("未知的上传方式.");
        }
        String uploadId = String.valueOf(map.get("uploadId"));
        List<String> partList = IntStream.range(0, parts).mapToObj(index -> String.valueOf(index)).collect(Collectors.toList());
        redisUtil.set(uploadId, partList, 60 * 60 * 24);
        return Result.ok(map);
    }

    /**
     * 上传分片文件
     *
     * @param httpServletRequest
     * @param uploadId           上传Id
     * @param partNumber         分片文件编号
     * @param filename           文件名称
     * @return
     */
    @SneakyThrows
    @PostMapping(path = "/uploadPart")
    public Result<?> upload(HttpServletRequest httpServletRequest, @RequestParam String uploadId, @RequestParam Integer partNumber, @RequestParam String filename) {
        log.info("uploadId {}. partNumber {}. filename {}", uploadId, partNumber, filename);
        Object object = redisUtil.get(uploadId);
        if (object instanceof List) {
            if (((List) object).remove(String.valueOf(partNumber))) {
                StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
                MultipartHttpServletRequest multipartHttpServletRequest = resolver.resolveMultipart(httpServletRequest);
                // 全部文件请求体
                Map<String, MultipartFile> multipartFileMap = multipartHttpServletRequest.getFileMap();
                MultipartFile multipartFile = multipartFileMap.get("file");
                log.info("File size {}", multipartFile.getInputStream().available());
                if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
                    MinioUtil.upload(uploadId, filename, partNumber, FileCopyUtils.copyToByteArray(multipartFile.getInputStream()));
                } else if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
                    this.uploadPartLocal(uploadId, partNumber, filename, multipartFile.getInputStream());
                } else {
                    return Result.error("未知的上传方式.");
                }
                redisUtil.set(uploadId, object, 60 * 60 * 24);
            }
        }
        return Result.ok();
    }

    /**
     * 合并分片文件
     *
     * @param fileMd5  文件Md5（用于文件秒传）
     * @param parts    分片数量
     * @param filename 文件名称
     * @param uploadId 上传Id
     * @return
     */
    @GetMapping(path = "/complete")
    public Result<?> complete(@RequestParam String fileMd5, @RequestParam Integer parts, @RequestParam String filename, @RequestParam String uploadId) {
        String url = null;
        if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
            url = MinioUtil.complete(parts, filename, uploadId);
        } else if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
            url = this.completeLocal(parts, filename, uploadId);
        } else {
            return Result.error("未知的上传方式.");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        // 文件MD5 + 用户Id作为文件唯一凭证，用于后续文件秒传
        String fileKey = fileMd5 + sysUser.getId();
        redisUtil.set(fileKey, url, 24 * 60 * 60);
        return Result.OK("", url);
    }

    /**
     * 本地文件上传
     *
     * @param mf      文件
     * @param bizPath 自定义路径
     * @return
     */
    private String uploadLocal(MultipartFile mf, String bizPath) {
        try {
            String ctxPath = uploadpath;
            String fileName = null;
            File file = new File(ctxPath + File.separator + bizPath + File.separator);
            if (!file.exists()) {
                // 创建文件根目录
                file.mkdirs();
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            orgName = CommonUtils.getFileName(orgName);
            if (orgName.indexOf(SymbolConstant.SPOT) != -1) {
                fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
            } else {
                fileName = orgName + "_" + System.currentTimeMillis();
            }
            String savePath = file.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            FileCopyUtils.copy(mf.getBytes(), savefile);
            String dbpath = null;
            if (oConvertUtils.isNotEmpty(bizPath)) {
                dbpath = bizPath + File.separator + fileName;
            } else {
                dbpath = fileName;
            }
            if (dbpath.contains(SymbolConstant.DOUBLE_BACKSLASH)) {
                dbpath = dbpath.replace(SymbolConstant.DOUBLE_BACKSLASH, SymbolConstant.SINGLE_SLASH);
            }
            return dbpath;
        } catch (IOException e) {
            //log.error(e.getMessage(), e);
            throw new JeecgBootException(e);
        }
//        return "";
    }

    // ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ [本地] 大文件，分片上传，文件秒传 ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓ ↓↓↓

    @SneakyThrows(value = {FileNotFoundException.class, IOException.class})
    private void uploadPartLocal(String uploadId, int partNumber, String filename, InputStream inputStream) {
        String folder = uploadpath + "/" + uploadId;
        if (new File(folder).exists()) {
            filename = folder + "/" + filename + partNumber;
            try (FileOutputStream fileOutputStream = new FileOutputStream(filename)) {
                // 文件流
                byte[] bytes = FileCopyUtils.copyToByteArray(inputStream);
                fileOutputStream.write(bytes);
            }
        } else {
            throw new JeecgBootException("未进行文件分片操作.");
        }
    }

    private Map<String, Object> fragmentLocal(int parts, @Nonnull String filename) {
        // 上传Id
        String uploadId = UUIDGenerator.generate();
        // 分片信息
        String[] parameters = IntStream.range(0, parts).mapToObj(index -> "partNumber=" + index).toArray(String[]::new);
        // 创建分片文件夹
        if (new File(uploadpath + "/" + uploadId).mkdirs()) {
            return new HashMap<String, Object>(2) {{
                this.put("uploadId", uploadId);
                this.put("parameters", parameters);
            }};
        }
        throw new JeecgBootException("文件分片失败.");
    }

    @SneakyThrows(value = {IOException.class})
    private String completeLocal(int parts, @Nonnull String filename, @Nonnull String uploadId) {
        File folder = new File(uploadpath + "/" + uploadId);
        // 获取分片文件
        Collection<File> files = FileUtils.listFiles(folder, TrueFileFilter.INSTANCE, FalseFileFilter.FALSE);
        Assert.isTrue(CollectionUtils.isNotEmpty(files) && files.size() == parts, "未上传所有分片文件.");
        // 文件分割
        String fileSplit = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + "/" + System.currentTimeMillis() + filename;
        // 创建文件
        File completeFile = this.createNewFileLocal(uploadpath + "/" + fileSplit);
        RandomAccessFile writeFile = new RandomAccessFile(completeFile, "rw");
        // 合并文件
        files.stream().sorted(Comparator.comparingInt(o -> Integer.parseInt(o.getName().replaceAll(filename, ""))))
                .forEach(partFile -> this.writeLocal(partFile, writeFile));
        writeFile.close();
        // 删除分片文件
        FileUtils.forceDelete(folder);
        return fileSplit;
    }

    /**
     * 合并文件
     *
     * @param partFile  分片文件
     * @param writeFile 合并文件
     */
    @SneakyThrows(value = {IOException.class})
    private void writeLocal(File partFile, RandomAccessFile writeFile) {
        byte[] bytes = new byte[1024];
        RandomAccessFile readFile = new RandomAccessFile(partFile, "r");
        int length;
        while ((length = readFile.read(bytes)) != -1) {
            writeFile.write(bytes, 0, length);
        }
        readFile.close();
    }

    /**
     * 创建文件
     *
     * @param path 文件路径
     * @return 文件
     */
    @SneakyThrows(value = {IOException.class})
    private File createNewFileLocal(String path) {
        File file = new File(path);
        if (!file.exists()) {
            if (!file.getParentFile().exists()) {
                Assert.isTrue(file.getParentFile().mkdirs(), "Fail to create folder.");
            }
            Assert.isTrue(file.createNewFile(), "Fail to create file.");
        }
        return file;
    }

    // ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ [本地] 大文件，分片上传，文件秒传 ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑ ↑↑↑

//	@PostMapping(value = "/upload2")
//	public Result<?> upload2(HttpServletRequest request, HttpServletResponse response) {
//		Result<?> result = new Result<>();
//		try {
//			String ctxPath = uploadpath;
//			String fileName = null;
//			String bizPath = "files";
//			String tempBizPath = request.getParameter("biz");
//			if(oConvertUtils.isNotEmpty(tempBizPath)){
//				bizPath = tempBizPath;
//			}
//			String nowday = new SimpleDateFormat("yyyyMMdd").format(new Date());
//			File file = new File(ctxPath + File.separator + bizPath + File.separator + nowday);
//			if (!file.exists()) {
//				file.mkdirs();// 创建文件根目录
//			}
//			MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//			MultipartFile mf = multipartRequest.getFile("file");// 获取上传文件对象
//			String orgName = mf.getOriginalFilename();// 获取文件名
//			fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
//			String savePath = file.getPath() + File.separator + fileName;
//			File savefile = new File(savePath);
//			FileCopyUtils.copy(mf.getBytes(), savefile);
//			String dbpath = bizPath + File.separator + nowday + File.separator + fileName;
//			if (dbpath.contains("\\")) {
//				dbpath = dbpath.replace("\\", "/");
//			}
//			result.setMessage(dbpath);
//			result.setSuccess(true);
//		} catch (IOException e) {
//			result.setSuccess(false);
//			result.setMessage(e.getMessage());
//			log.error(e.getMessage(), e);
//		}
//		return result;
//	}

    /**
     * 预览图片&下载文件
     * 请求地址：http://localhost:8080/common/static/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
     *
     * @param request
     * @param response
     */
    @GetMapping(value = "/static/**")
    public void view(HttpServletRequest request, HttpServletResponse response) {
        // ISO-8859-1 ==> UTF-8 进行编码转换
        String imgPath = extractPathFromPattern(request);
        if (oConvertUtils.isEmpty(imgPath) || CommonConstant.STRING_NULL.equals(imgPath)) {
            return;
        }
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "").replace("../", "");
            if (imgPath.endsWith(SymbolConstant.COMMA)) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String filePath = uploadpath + File.separator + imgPath;
            File file = new File(filePath);
            if (!file.exists()) {
                response.setStatus(404);
                throw new RuntimeException("文件[" + imgPath + "]不存在..");
            }
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("预览文件失败" + e.getMessage());
            response.setStatus(404);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

    }

    /**
     * 预览文件
     * 20210526 create by zhaowl for 预览文件。与下载文件只是差在response的设置
     * 请求地址：http://localhost:8080/common/preview/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
     *
     * @param request
     * @param response
     */
    @GetMapping(value = "/preview/**")
    public void preview(HttpServletRequest request, HttpServletResponse response) {
        // ISO-8859-1 ==> UTF-8 进行编码转换
        String imgPath = extractPathFromPattern(request);
        if (oConvertUtils.isEmpty(imgPath) || imgPath == "null") {
            return;
        }
        // 其余处理略
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            imgPath = imgPath.replace("..", "");
            if (imgPath.endsWith(",")) {
                imgPath = imgPath.substring(0, imgPath.length() - 1);
            }
            String filePath = uploadpath + File.separator + imgPath;
            File file = new File(filePath);
            if (!file.exists()) {
                response.setStatus(404);
                throw new RuntimeException("文件不存在..");
            }
            /* 20210526 create by zhaowl for 支持预览 start */
            // 服务端添加Accept-Ranges、ETag这两个响应头，以保证客户端和服务端将此下载识别为可以断点续传的下载
            response.addHeader("Accept-Ranges", "bytes");//告知下载客户端这是一个可以恢复续传的下载
            response.addHeader("ETag", "" + (filePath + file.lastModified()).hashCode());//保存文件的唯一标识，以便续传请求时对文件进行验证
            response.addHeader("Last-Modified", "" + file.lastModified());//可选响应头，存放服务端文件的最后修改时间，用于验证
            // 根据文件获取对应contentType
            String contentType = Files.probeContentType(Paths.get(filePath));
            response.setContentType(contentType);
            // Content-Disposition，只设置filename，去掉attachment，否则仍然是下载而不是预览；也可以不设置Content-Disposition
            response.addHeader("Content-Disposition", "fileName=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
            /* 20210526 create by zhaowl for 支持预览 end */
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("预览文件失败" + e.getMessage());
            response.setStatus(404);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

    }

//	/**
//	 * 下载文件
//	 * 请求地址：http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
//	 *
//	 * @param request
//	 * @param response
//	 * @throws Exception
//	 */
//	@GetMapping(value = "/download/**")
//	public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
//		// ISO-8859-1 ==> UTF-8 进行编码转换
//		String filePath = extractPathFromPattern(request);
//		// 其余处理略
//		InputStream inputStream = null;
//		OutputStream outputStream = null;
//		try {
//			filePath = filePath.replace("..", "");
//			if (filePath.endsWith(",")) {
//				filePath = filePath.substring(0, filePath.length() - 1);
//			}
//			String localPath = uploadpath;
//			String downloadFilePath = localPath + File.separator + filePath;
//			File file = new File(downloadFilePath);
//	         if (file.exists()) {
//	         	response.setContentType("application/force-download");// 设置强制下载不打开            
//	 			response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
//	 			inputStream = new BufferedInputStream(new FileInputStream(file));
//	 			outputStream = response.getOutputStream();
//	 			byte[] buf = new byte[1024];
//	 			int len;
//	 			while ((len = inputStream.read(buf)) > 0) {
//	 				outputStream.write(buf, 0, len);
//	 			}
//	 			response.flushBuffer();
//	         }
//
//		} catch (Exception e) {
//			log.info("文件下载失败" + e.getMessage());
//			// e.printStackTrace();
//		} finally {
//			if (inputStream != null) {
//				try {
//					inputStream.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			if (outputStream != null) {
//				try {
//					outputStream.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//		}
//
//	}

    /**
     * @param modelAndView
     * @return
     * @功能：pdf预览Iframe
     */
    @RequestMapping("/pdf/pdfPreviewIframe")
    public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
        modelAndView.setViewName("pdfPreviewIframe");
        return modelAndView;
    }

    /**
     * 把指定URL后的字符串全部截断当成参数
     * 这么做是为了防止URL中包含中文或者特殊字符（/等）时，匹配不了的问题
     *
     * @param request
     * @return
     */
    private static String extractPathFromPattern(final HttpServletRequest request) {
        String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }

}
